package com.dny.asmtop.op;

import com.dny.asmtop.Command;
import com.dny.asmtop.MethodContext;
import com.dny.asmtop.Preconditions;
import com.dny.asmtop.Primitives;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;

import java.util.Objects;

import static jdk.internal.org.objectweb.asm.Type.getType;

/**
 * Created by jlutt on 2018-01-16.
 * 返回一个常量值
 * @author jlutt
 */
public class CommandValue implements Command {

  private final Object value;
  private String staticConstantField;

  public CommandValue(Object value) {
    Preconditions.checkNotNull(value);
    this.value = value;
  }

  @Override
  public Type type(MethodContext context) {
    if (value instanceof String) {
      return getType(String.class);
    } else if (value instanceof Type) {
      return (Type) value;
    } else {
      return getType(Primitives.unwrap(value.getClass()));
    }
  }

  @Override
  public Type generator(MethodContext context) {
    GeneratorAdapter g = context.getGeneratorAdapter();

    Type type = type(context);
    if (value instanceof Byte) {
      g.push((Byte) value);
    } else if (value instanceof Short) {
      g.push((Short) value);
    } else if (value instanceof Integer) {
      g.push((Integer) value);
    } else if (value instanceof Long) {
      g.push((Long) value);
    } else if (value instanceof Float) {
      g.push((Float) value);
    } else if (value instanceof Double) {
      g.push((Double) value);
    } else if (value instanceof Boolean) {
      g.push((Boolean) value);
    } else if (value instanceof Character) {
      g.push((Character) value);
    } else if (value instanceof String) {
      g.push((String) value);
    } else if (value instanceof Type) {
      g.push((Type) value);
    } else if (value instanceof Enum) {
      g.getStatic(type, ((Enum) value).name(), type);
    } else {
      if (staticConstantField == null) {
        staticConstantField = "$STATIC_CONSTANT_" + (context.getStaticConstants().size() + 1);
        context.addStaticConstant(staticConstantField, value);
      }
      g.getStatic(context.getThisType(), staticConstantField, getType(value.getClass()));
    }
    return type;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    CommandValue that = (CommandValue) o;
    return Objects.equals(value, that.value);
  }

  @Override
  public int hashCode() {
    return Objects.hash(value);
  }
}
